'    Copyright 2008 Jan Molnar <jan.molnar@abds.de>
'
'    This file is part of JCQ.

'    JCQ is free software: you can redistribute it and/or modify
'    it under the terms of the GNU General Public License as published by
'    the Free Software Foundation, either version 2 of the License, or
'    (at your option) any later version.

'    JCQ is distributed in the hope that it will be useful,
'    but WITHOUT ANY WARRANTY; without even the implied warranty of
'    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'    GNU General Public License for more details.

'    You should have received a copy of the GNU General Public License
'    along with JCQ. If not, see <http://www.gnu.org/licenses/>.

Imports JCsTools.Xml.Formatter
Imports System.Xml

Public Class BaseStorageItemFormatter
    Inherits DefaultReferenceFormatter

    Private ReadOnly _Context As Interfaces.IContext

    Private ReadOnly ignoredKeys As List(Of String) = New List(Of String)(New String() {"Status"})

    Public Sub New(ByVal context As Interfaces.IContext, ByVal parent As JCsTools.Xml.Formatter.XmlSerializer, ByVal type As Type)
        MyBase.New(parent, type)
        _Context = context
    End Sub

    Protected Overrides Sub SerializeProperties(ByVal graph As Object, ByVal writer As System.Xml.XmlWriter)
        Dim item As BaseStorageItem
        Dim attributes As Hashtable

        item = DirectCast(graph, BaseStorageItem)

        writer.WriteAttributeString("name", item.Name)
        writer.WriteAttributeString("identifier", item.Identifier)

        writer.WriteStartElement("Attributes")

        attributes = item.Attributes

        For Each key As String In attributes.Keys
            If ignoredKeys.Contains(key) Then Continue For

            Dim value As Object = attributes(key)
            If value Is Nothing Then Continue For

            Dim type As Type = value.GetType

            writer.WriteStartElement(key)

            WriteTypeAttribute(value, type, writer)

            writer.WriteAttributeString("key", key)

            If type.IsValueType Then
                Dim formatter As IValueFormatter = Serializer.GetValueFormatter(type)

                writer.WriteAttributeString("value", formatter.Serialize(value))
            ElseIf type Is GetType(String) Then
                writer.WriteAttributeString("value", DirectCast(value, String))
            Else
                writer.WriteAttributeString("value", Serializer.GetSerializeObjectId(value).ToString)
            End If

            writer.WriteEndElement()
        Next

        writer.WriteEndElement()
    End Sub

    'Protected Overrides Sub SerializeProperties(ByVal graph As Object, ByVal element As System.Xml.XmlElement)
    '    ' name, identity, attributes

    '    Dim item As BaseStorageItem
    '    Dim document As XmlDocument = element.OwnerDocument

    '    item = DirectCast(graph, BaseStorageItem)

    '    Dim properties As PropertyDescriptorCollection = TypeDescriptor.GetProperties(graph)

    '    Dim propertyAttribute As XmlAttribute

    '    Dim nameProperty As PropertyDescriptor = properties("Name")
    '    Dim identifierProperty As PropertyDescriptor = properties("Identifier")
    '    Dim attributesProperty As PropertyDescriptor = properties("Attributes")

    '    propertyAttribute = document.CreateAttribute("name")
    '    propertyAttribute.Value = CStr(nameProperty.GetValue(graph))
    '    element.Attributes.Append(propertyAttribute)

    '    propertyAttribute = document.CreateAttribute("identifier")
    '    propertyAttribute.Value = CStr(identifierProperty.GetValue(graph))
    '    element.Attributes.Append(propertyAttribute)

    '    Dim attributes As Hashtable = DirectCast(attributesProperty.GetValue(graph), Hashtable)

    '    Dim attributesElement As XmlElement = document.CreateElement("Attributes")

    '    For Each key As String In attributes.Keys
    '        If ignoredKeys.Contains(key) Then Continue For

    '        Dim attributeElement As XmlElement

    '        Dim value As Object = attributes(key)
    '        If value Is Nothing Then Continue For

    '        Dim type As Type = value.GetType

    '        attributeElement = document.CreateElement(key)

    '        Me.AppendTypeAttribute(value, attributeElement)

    '        If type.IsValueType Or type Is GetType(String) Then
    '            Dim f As IValueFormatter = Formatter.GetValueFormatter(type)

    '            Dim keyAttribute As XmlAttribute = document.CreateAttribute("key")
    '            keyAttribute.Value = key
    '            attributeElement.Attributes.Append(keyAttribute)

    '            Dim valueAttribute As XmlAttribute = document.CreateAttribute("value")
    '            valueAttribute.Value = f.Serialize(value)
    '            attributeElement.Attributes.Append(valueAttribute)

    '            'AppendValueAttribute(attributeElement, f.Serialize(value))
    '        Else
    '            Dim keyAttribute As XmlAttribute = document.CreateAttribute("key")
    '            keyAttribute.Value = key
    '            attributeElement.Attributes.Append(keyAttribute)

    '            Dim valueAttribute As XmlAttribute = document.CreateAttribute("value")
    '            valueAttribute.Value = CStr(Formatter.GetObjectId(value))
    '            attributeElement.Attributes.Append(valueAttribute)

    '            'AppendValueAttribute(attributeElement, CStr(_Context.GetObjectId(value)))
    '        End If

    '        attributesElement.AppendChild(attributeElement)
    '    Next

    '    element.AppendChild(attributesElement)
    'End Sub

    Protected Overrides Function CreateObject(ByVal type As System.Type, ByVal reader As XmlReader) As Object
        Dim identifier As String = reader.GetAttribute("identifier")

        Return _Context.GetService(Of Interfaces.IStorageService).GetContactByIdentifier(identifier)
    End Function

    Protected Overrides Sub DeserializeProperties(ByVal graph As Object, ByVal reader As XmlReader)
        Dim contact As IcqContact = DirectCast(graph, IcqContact)

        contact.Identifier = reader.GetAttribute("identifier")
        contact.Name = reader.GetAttribute("name")

        If reader.IsEmptyElement Then Return ' no data ...

        Dim type As Type

        Do While reader.Read AndAlso reader.NodeType = XmlNodeType.Element
            reader.MoveToFirstAttribute() ' This is always __type
            type = GetObjectType(reader)

            If type Is Nothing Then Continue Do

            Dim key As String
            Dim value As String

            reader.MoveToNextAttribute() ' This is always key
            key = reader.Value

            reader.MoveToNextAttribute() ' This is always value
            value = reader.Value

            If type.IsValueType Then
                Dim formatter As IValueFormatter = Serializer.GetValueFormatter(type)

                contact.Attributes(key) = formatter.Deserialize(value)
            ElseIf type Is GetType(String) Then
                contact.Attributes(key) = value
            Else
                Dim fixup = New HashtableItemFixUp(key, Integer.Parse(value), contact.Attributes)

                Serializer.RegisterCustomFixUp(fixup)
            End If
        Loop
    End Sub
End Class

Public Class HashtableItemFixUp
    Implements IFixUp

    Private ReadOnly _Hashtable As Hashtable
    Private ReadOnly _ItemId As Integer
    Private ReadOnly _Key As String

    Public Sub New(ByVal key As String, ByVal itemId As Integer, ByVal hashtable As Hashtable)
        _Key = Key
        _ItemId = itemId
        _Hashtable = hashtable
    End Sub

    Public ReadOnly Property Hashtable() As Hashtable
        Get
            Return _Hashtable
        End Get
    End Property

    Public ReadOnly Property Key() As String
        Get
            Return _Key
        End Get
    End Property

    Public ReadOnly Property ItemId() As Integer
        Get
            Return _ItemId
        End Get
    End Property

    Public Sub Execute(ByVal serializer As Xml.Formatter.ISerializer) Implements Xml.Formatter.IFixUp.Execute
        Dim item As Object = serializer.GetDeserializeObjectById(ItemId)

        _Hashtable.Add(Key, item)
    End Sub
End Class